home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 001 / pibt40s5.arc / SENDKER1.MOD < prev    next >
Text File  |  1987-09-08  |  30KB  |  725 lines

  1. (*----------------------------------------------------------------------*)
  2. (*              Send_Kermit_File --- Upload file using Kermit           *)
  3. (*----------------------------------------------------------------------*)
  4.  
  5. PROCEDURE Send_Kermit_File;
  6.  
  7. (*----------------------------------------------------------------------*)
  8. (*                                                                      *)
  9. (*     Procedure:  Send_Kermit_File                                     *)
  10. (*                                                                      *)
  11. (*     Purpose:    Uploads file to remote using Kermit protocol         *)
  12. (*                                                                      *)
  13. (*     Calling Sequence:                                                *)
  14. (*                                                                      *)
  15. (*        Send_Kermit_File;                                             *)
  16. (*                                                                      *)
  17. (*----------------------------------------------------------------------*)
  18.  
  19. CONST
  20.    EOF_Packet   = 'Z';
  21.    Break_Packet = 'B';
  22.  
  23. CONST
  24.    Send_Quit_Item = 6;
  25.  
  26. VAR
  27.    Buffer_Pos    : INTEGER;
  28.    Buffer_Size   : INTEGER;
  29.    Write_Count   : INTEGER;
  30.    Err           : INTEGER;
  31.    Local_Save    : Saved_Screen_Ptr;
  32.    Local_Save_2  : Saved_Screen_Ptr;
  33.    File_Pattern  : AnyStr;
  34.    Stop_Send     : BOOLEAN;
  35.    File_Entry    : Directory_Record;
  36.    OK_File       : BOOLEAN;
  37.    Try           : INTEGER;
  38.    Send_Done     : BOOLEAN;
  39.    Kermit_Menu   : Menu_Type;
  40.    I             : INTEGER;
  41.    J             : INTEGER;
  42.    Kermit_Done   : BOOLEAN;
  43.    Host_Count    : INTEGER;
  44.    Menu_Choice   : INTEGER;
  45.    Long_Buffer   : BOOLEAN;
  46.    Buffer_Length : INTEGER;
  47.    Read_Buffer   : File_Handle_Buffer_Ptr;
  48.    No_More_Chars : BOOLEAN;
  49.    Buffer_Total  : REAL;
  50.    Full_Name     : AnyStr;
  51.    Buffer_Num_Actual : REAL;
  52.    Total_Time    : REAL;
  53.  
  54. (*----------------------------------------------------------------------*)
  55. (*       Get_Kermit_File_Name --- Construct file name to Kermit form    *)
  56. (*----------------------------------------------------------------------*)
  57.  
  58. PROCEDURE Get_Kermit_File_Name( VAR OK_File : BOOLEAN );
  59.  
  60. (*----------------------------------------------------------------------*)
  61. (*                                                                      *)
  62. (*     Procedure:  Get_Kermit_File_Name                                 *)
  63. (*                                                                      *)
  64. (*     Purpose:    Gets name of next file to be transferred             *)
  65. (*                                                                      *)
  66. (*     Calling Sequence:                                                *)
  67. (*                                                                      *)
  68. (*        Get_Kermit_File_Name( VAR OK_File : BOOLEAN );                *)
  69. (*                                                                      *)
  70. (*           OK_File --- TRUE if file is OK to be transferred           *)
  71. (*                                                                      *)
  72. (*     Calls:                                                           *)
  73. (*                                                                      *)
  74. (*        Scan_Xfer_List                                                *)
  75. (*                                                                      *)
  76. (*     Remarks:                                                         *)
  77. (*                                                                      *)
  78. (*        The global variable 'FileName' gets the file name.            *)
  79. (*                                                                      *)
  80. (*----------------------------------------------------------------------*)
  81.  
  82. VAR
  83.    I: INTEGER;
  84.  
  85. BEGIN (* Get_Kermit_File_Name *)
  86.  
  87.    I             := 1;
  88.    FileName      := '';
  89.  
  90.    WHILE( File_Entry.File_Name[I] <> CHR( 0 ) ) AND ( I <= 12 ) DO
  91.       BEGIN
  92.          FileName := FileName + File_Entry.File_Name[I];
  93.          I        := SUCC( I );
  94.       END;
  95.  
  96.    OK_File := ( File_Entry.File_Attr AND
  97.                 ( Dir_Attr_Volume_Label + Dir_Attr_Subdirectory ) = 0 );
  98.  
  99.                                    (* If host mode, make sure file *)
  100.                                    (* is on xferlist!              *)
  101.    IF Host_Mode THEN
  102.       IF ( Privilege <> 'S' ) THEN
  103.          OK_File := OK_File AND ( Scan_Xfer_List( FileName ) > 0 );
  104.  
  105. END   (* Get_Kermit_File_Name *);
  106.  
  107. (*----------------------------------------------------------------------*)
  108. (*                 Get_File_Data --- get data from file                 *)
  109. (*----------------------------------------------------------------------*)
  110.  
  111. PROCEDURE Get_File_Data;
  112.  
  113. (*----------------------------------------------------------------------*)
  114. (*                                                                      *)
  115. (*     Procedure:  Get_File_Data                                        *)
  116. (*                                                                      *)
  117. (*     Purpose:    Gets next buffer of data from file being uploaded    *)
  118. (*                                                                      *)
  119. (*     Calling Sequence:                                                *)
  120. (*                                                                      *)
  121. (*        Get_File_Data;                                                *)
  122. (*                                                                      *)
  123. (*     Calls:                                                           *)
  124. (*                                                                      *)
  125. (*        Read_File_Handle                                              *)
  126. (*        Close_File_Handle                                             *)
  127. (*                                                                      *)
  128. (*     Remarks:                                                         *)
  129. (*                                                                      *)
  130. (*        The global variable 'Send_Packet_Ptr^' gets the next batch    *)
  131. (*        of data.  'Read_Buffer^' holds the current 'Buffer_Size'      *)
  132. (*        characters read in.                                           *)
  133. (*                                                                      *)
  134. (*----------------------------------------------------------------------*)
  135.  
  136. VAR
  137.    Char_Count   : INTEGER;
  138.    Save_Char    : Byte;
  139.    Temp_Data    : STRING[120];
  140.    End_Of_File  : BOOLEAN;
  141.    Err          : INTEGER;
  142.    NRead        : INTEGER;
  143.    Ascii_File   : BOOLEAN;
  144.    L            : INTEGER;
  145.    MaxData      : INTEGER;
  146.    Repeat_Count : INTEGER;
  147.    Packet_Count : INTEGER;
  148.    EChar_Count  : INTEGER;
  149.  
  150. (*----------------------------------------------------------------------*)
  151.  
  152. FUNCTION NextChar: BYTE;
  153.  
  154. BEGIN (* NextChar *)
  155.                                    (* See if current buffer exhausted *)
  156.  
  157.    IF ( Buffer_Pos >= Buffer_Size ) AND ( NOT End_Of_File ) THEN
  158.       BEGIN
  159.                                    (* Read Sector_size chars from file  *)
  160.                                    (* to be sent.                       *)
  161.  
  162.          NRead       := Buffer_Size;
  163.          Err         := Read_File_Handle( XFile_Handle, Read_Buffer^, NRead );
  164.          Buffer_Pos  := 0;
  165.          Buffer_Size := NRead;
  166.          End_Of_File := ( NRead <= 0 );
  167.  
  168.       END;
  169.                                    (* See if anything to be sent *)
  170.  
  171.    IF ( Buffer_Pos < Buffer_Size ) THEN
  172.       BEGIN
  173.                                    (* Pick up next character *)
  174.  
  175.          Buffer_Pos    := SUCC( Buffer_Pos );
  176.          NextChar      := Read_Buffer^[ Buffer_Pos ];
  177.          Char_Count    := SUCC( Char_Count );
  178.          No_More_Chars := FALSE;
  179.  
  180.       END
  181.    ELSE
  182.       BEGIN
  183.          No_More_Chars := TRUE;
  184.          NextChar      := ORD( ^Z );
  185.       END;
  186.  
  187. END   (* NextChar *);
  188.  
  189. (*----------------------------------------------------------------------*)
  190.  
  191. FUNCTION PeekChar : BYTE;
  192.  
  193. BEGIN (* PeekChar *)
  194.  
  195.    IF ( Buffer_Pos < Buffer_Size ) THEN
  196.       PeekChar := Read_Buffer^[Buffer_Pos + 1]
  197.    ELSE
  198.       PeekChar := ( Read_Buffer^[Buffer_Pos] + 1 ) AND $FF;
  199.  
  200. END   (* PeekChar *);
  201.  
  202. (*----------------------------------------------------------------------*)
  203.  
  204. PROCEDURE Encode_Kermit_Character( A: BYTE );
  205.  
  206. VAR
  207.    A8: BYTE;
  208.    A7: BYTE;
  209.  
  210. BEGIN (* Encode_Kermit_Character *)
  211.  
  212.                                    (* Separate 7 bits from high bit *)
  213.    A7 := A AND $7F;
  214.    A8 := A AND $80;
  215.                                    (* Perform 8th bit quoting *)
  216.    IF Quoting THEN
  217.       IF ( A8 <> 0 ) THEN
  218.          BEGIN
  219.             Packet_Count                     := SUCC( Packet_Count );
  220.             Send_Packet_Ptr^[Packet_Count]   := Kermit_Quote_8_Char;
  221.             A                                := A7;
  222.          END;
  223.                                    (* Perform control quoting *)
  224.  
  225.    IF ( A7 < SP ) OR ( A7 = DEL ) THEN
  226.       BEGIN
  227.          Packet_Count                     := SUCC( Packet_Count );
  228.          Send_Packet_Ptr^[Packet_Count]   := Kermit_Quote_Char;
  229.          A                                := A XOR 64;
  230.       END;
  231.                                    (* Prefix the control prefix *)
  232.  
  233.    IF ( A7 = ORD( Kermit_Quote_Char ) ) THEN
  234.       BEGIN
  235.          Packet_Count                     := SUCC( Packet_Count );
  236.          Send_Packet_Ptr^[Packet_Count]   := Kermit_Quote_Char;
  237.       END;
  238.  
  239.    IF Repeating THEN
  240.       IF ( A7 = ORD( His_Repeat_Char ) ) THEN
  241.          BEGIN
  242.             Packet_Count                     := SUCC( Packet_Count );
  243.             Send_Packet_Ptr^[Packet_Count]   := Kermit_Quote_Char;
  244.          END;
  245.                                    (* Prefix the 8-bit quote char *)
  246.    IF Quoting THEN
  247.       IF ( A7 = ORD( Kermit_Quote_8_Char ) ) THEN
  248.          BEGIN
  249.             Packet_Count                     := SUCC( Packet_Count );
  250.             Send_Packet_Ptr^[Packet_Count]   := Kermit_Quote_Char;
  251.          END;
  252.                                    (* Finally, insert either 8-bit or  *)
  253.                                    (* 7-bit version of character into  *)
  254.                                    (* packet.                          *)
  255.  
  256.    Packet_Count                     := SUCC( Packet_Count );
  257.    Send_Packet_Ptr^[Packet_Count]   := CHR( A );
  258.  
  259.                                    (* Increment count of encoded chars *)
  260.  
  261.    EChar_Count                      := SUCC( EChar_Count );
  262.  
  263. END   (* Encode_Kermit_Character *);
  264.  
  265. (*----------------------------------------------------------------------*)
  266.  
  267. BEGIN (* Get_File_Data *)
  268.                                    (* Packet length        *)
  269.    IF Kermit_Do_Long_Blocks THEN
  270.       BEGIN
  271.          Packet_Count       := 7;
  272.          MaxData            := His_Kermit_MaxLX1 * 95 + His_Kermit_MaxLX2 - 3;
  273.       END
  274.    ELSE
  275.       BEGIN
  276.          Packet_Count       := 4;
  277.          MaxData            := Kermit_Packet_Size;
  278.       END;
  279.                                    (* Maximum length allowed for data *)
  280.  
  281.    MaxData := MaxData - 3 - ( ORD( Kermit_Chk_Type ) - ORD('0') );
  282.  
  283.    IF Repeating THEN
  284.       MaxData := MaxData - 2;
  285.                                    (* Remember if ascii transfer *)
  286.  
  287.    Ascii_File          := ( Kermit_File_Type_Var = Kermit_Ascii );
  288.  
  289.                                    (* Set data type packet *)
  290.    Send_Packet_Ptr^[4] := 'D';
  291.                                    (* Characters from file *)
  292.    Char_Count          := 0;
  293.                                    (* Encoded characters this packet *)
  294.    EChar_Count         := 0;
  295.                                    (* Repeat count starts at 0 *)
  296.    Repeat_Count        := 0;
  297.                                    (* Not end of file yet *)
  298.    End_Of_File         := FALSE;
  299.                                    (* Get next batch of characters *)
  300.                                    (* from file                    *)
  301.    REPEAT
  302.                                    (* See if anything to be sent *)
  303.       Save_Char := NextChar;
  304.                                    (* Make sure to stop at ^Z = EOF *)
  305.                                    (* on text files.                *)
  306.  
  307.       IF Ascii_File AND ( Save_Char = ORD( ^Z ) ) THEN
  308.          BEGIN
  309.             End_Of_File        := TRUE;
  310.             No_More_Chars      := TRUE;
  311. {
  312.             IF Kermit_Debug THEN
  313.                Write_Log('Found Ctrl-Z for Ascii file.', TRUE, FALSE);
  314. }
  315.          END;
  316.                                    (* Handle repeat quoting here *)
  317.       IF ( NOT No_More_Chars ) THEN
  318.          IF Repeating THEN
  319.             BEGIN
  320.  
  321.                Repeat_Count := 1;
  322.  
  323.                WHILE ( ( PeekChar = Save_Char ) AND ( Repeat_Count < 94 ) ) DO
  324.                   BEGIN
  325.                      Save_Char    := NextChar;
  326.                      Repeat_Count := SUCC( Repeat_Count );
  327.                   END;
  328.  
  329.                CASE Repeat_Count OF
  330.                   1:    Encode_Kermit_Character( Save_Char );
  331.                   2:    BEGIN
  332.                            Encode_Kermit_Character( Save_Char );
  333.                            Encode_Kermit_Character( Save_Char );
  334.                         END;
  335.                   ELSE  BEGIN
  336.                            Packet_Count                     := SUCC( Packet_Count );
  337.                            Send_Packet_Ptr^[Packet_Count]   := His_Repeat_Char;
  338.                            Packet_Count                     := SUCC( Packet_Count );
  339.                            Send_Packet_Ptr^[Packet_Count]   := CHR( Repeat_Count + 32 );
  340.                            Encode_Kermit_Character( Save_Char );
  341.                         END;
  342.                END (* CASE *);
  343.  
  344.             END
  345.          ELSE                      (* Not a repeated character *)
  346.  
  347.             Encode_Kermit_Character( Save_Char );
  348.  
  349.    UNTIL ( End_Of_File AND No_More_Chars ) OR
  350.          ( Packet_Count >= MaxData );
  351.  
  352.                                    (* Record encoded character count *)
  353.  
  354.    Buffer_Num        := Buffer_Num        + Char_Count;
  355.    Buffer_Num_Actual := Buffer_Num_Actual + EChar_Count;
  356.  
  357.                                    (* Remember length of packet   *)
  358.  
  359.    IF ( Char_Count > 0 ) THEN
  360.       Send_Packet_Length := Packet_Count
  361.    ELSE
  362.       Send_Packet_Length := 0;
  363.                                    (* Remember if end of file AND *)
  364.                                    (* buffer exhausted.           *)
  365.  
  366.    IF ( End_Of_File AND No_More_Chars ) THEN
  367.       BEGIN
  368.          File_Done    := TRUE;
  369.          Err          := Close_File_Handle( XFile_Handle );
  370.          Buffer_Total := Buffer_Total + Buffer_Num;
  371.       END
  372.    ELSE
  373.       File_Done := FALSE;
  374.  
  375. END    (* Get_File_Data *);
  376.  
  377. (*----------------------------------------------------------------------*)
  378. (*          Kermit_Send_Init --- send initialization packet             *)
  379. (*----------------------------------------------------------------------*)
  380.  
  381. PROCEDURE Kermit_Send_Init;
  382.  
  383. (*----------------------------------------------------------------------*)
  384. (*                                                                      *)
  385. (*     Procedure:  Kermit_Send_Init                                     *)
  386. (*                                                                      *)
  387. (*     Purpose:    Sends transfer initialization packet to host.        *)
  388. (*                                                                      *)
  389. (*     Calling Sequence:                                                *)
  390. (*                                                                      *)
  391. (*        Kermit_Send_Init;                                             *)
  392. (*                                                                      *)
  393. (*     Calls:                                                           *)
  394. (*                                                                      *)
  395. (*        Build_Packet                                                  *)
  396. (*        Send_Packet                                                   *)
  397. (*        Receive_Packet                                                *)
  398. (*                                                                      *)
  399. (*----------------------------------------------------------------------*)
  400.  
  401. VAR
  402.    Quote_8       : CHAR;
  403.    Repeat_Char   : CHAR;
  404.    My_Attributes : CHAR;
  405.    Window_Size   : STRING[1];
  406.    LX1           : CHAR;
  407.    LX2           : CHAR;
  408.    Attributes    : BYTE;
  409.    Do_Win        : BOOLEAN;
  410.    Do_Long       : BOOLEAN;
  411.  
  412. BEGIN (* Kermit_Send_Init *)
  413.  
  414.    Packet_Num   := 0;
  415.    Try          := 0;
  416.    Quoting      := FALSE;
  417.                                    (* Ensure type 1 block check here *)
  418.    His_Chk_Type := '1';
  419.                                    (* 8-bit quoting off for 8,n,1   *)
  420.                                    (* and ascii file type transfers *)
  421.  
  422.    IF ( ( Parity <> 'N' ) OR ( Data_Bits <> 8 ) ) AND
  423.       ( Kermit_File_Type_Var = Kermit_Binary ) THEN
  424.       BEGIN
  425.          Quote_8 := Kermit_Quote_8_Char;
  426.          Quoting := TRUE;
  427.       END
  428.    ELSE                            (* Willing to quote if necessary *)
  429.       Quote_8 := 'Y';
  430.                                    (* If repeating data to be allowed *)
  431.  
  432.    Repeat_Char := Kermit_Repeat_Char;
  433.  
  434.                                    (* Capabilities                    *)
  435.    Attributes  := 8;
  436.                                    (* Set window size, long packets   *)
  437.                                    (* size.                           *)
  438.  
  439.    His_Kermit_Window_Size := Kermit_Window_Size;
  440.    His_Kermit_MaxLX1      := Kermit_Extended_Block DIV 95;
  441.    His_Kermit_MaxLX2      := Kermit_Extended_Block MOD 95;
  442.  
  443.    Window_Size := ' ';
  444.    Do_Win      := ( His_Kermit_Window_Size > 0 );
  445.    Do_Long     := ( ( His_Kermit_MaxLX1 > 0 ) OR ( His_Kermit_MaxLX2 > 0 ) );
  446.  
  447.    IF Do_Win THEN
  448.       BEGIN
  449.          Attributes  := Attributes + 4;
  450.          Window_Size := CHR( His_Kermit_Window_Size + 32 );
  451.       END;
  452.  
  453.    IF Do_Long THEN
  454.       BEGIN
  455.          Attributes := Attributes + 2;
  456.          LX1        := CHR( His_Kermit_MaxLX1 + 32 );
  457.          LX2        := CHR( His_Kermit_MaxLX2 + 32 );
  458.       END;
  459.  
  460.    My_Attributes    := CHR( Attributes + 32 );
  461.  
  462.                                    (* Construct initialization packet *)
  463.  
  464.    Send_Packet_Ptr^[ 4] := 'S';
  465.    Send_Packet_Ptr^[ 5] := CHR( Kermit_Packet_Size + 32         );
  466.    Send_Packet_Ptr^[ 6] := CHR( Kermit_TimeOut     + 32         );
  467.    Send_Packet_Ptr^[ 7] := CHR( Kermit_Npad        + 32         );
  468.    Send_Packet_Ptr^[ 8] := CHR( ORD( Kermit_Pad_Char ) XOR $40  );
  469.    Send_Packet_Ptr^[ 9] := CHR( ORD( Kermit_EOL      ) + 32     );
  470.    Send_Packet_Ptr^[10] := Kermit_Quote_Char;
  471.    Send_Packet_Ptr^[11] := Quote_8;
  472.    Send_Packet_Ptr^[12] := Kermit_Chk_Type;
  473.    Send_Packet_Ptr^[13] := Repeat_Char;
  474.    Send_Packet_Ptr^[14] := My_Attributes;
  475.  
  476.    Send_Packet_Length   := 14;
  477.  
  478.    IF ( Do_Win OR Do_Long ) THEN
  479.       BEGIN
  480.          Send_Packet_Ptr^[15] := Window_Size;
  481.          Send_Packet_Length   := 15;
  482.       END;
  483.  
  484.    IF Do_Long THEN
  485.       BEGIN
  486.          Send_Packet_Ptr^[16] := LX1;
  487.          Send_Packet_Ptr^[17] := LX2;
  488.          Send_Packet_Length   := 17;
  489.       END;
  490. {
  491.    IF Kermit_Debug THEN
  492.       Write_Log('My send-init packet = <' +
  493.                 COPY( Send_Packet_Ptr^, 1, Send_Packet_Length ) + '>',
  494.                 FALSE, FALSE );
  495. }
  496.    Build_Packet;
  497.  
  498.    REPEAT
  499.                                    (* Ensure type 1 block check here *)
  500.       His_Chk_Type := '1';
  501.                                    (* Assume bad until proved otherwise *)
  502.       ACK_OK := FALSE;
  503.                                    (* Send initialization packet *)
  504.       Send_Packet;
  505.                                    (* Check response *)
  506.       Receive_Packet;
  507.                                    (* If right response then check *)
  508.                                    (* if received packet jives     *)
  509.                                    (* with what we sent.           *)
  510.       IF ( Packet_OK AND
  511.          ( Kermit_Packet_Type = ACK_Pack ) AND
  512.          ( NOT Kermit_Abort ) ) THEN
  513.          Check_Init( ACK_OK );
  514.                                    (* Increment count of tries     *)
  515.       Try := SUCC( Try );
  516.  
  517.    UNTIL ACK_OK OR Kermit_Abort OR ( Try = Kermit_MaxTry );
  518.  
  519.                                    (* If OK, then get ready to send  *)
  520.                                    (* file header packet, else abort *)
  521.    IF ACK_OK THEN
  522.       Kermit_State := Send_File_Header
  523.    ELSE
  524.       BEGIN
  525.          Kermit_Abort := TRUE;
  526.          Kermit_State := Send_Break;
  527.       END;
  528.  
  529. END   (* Kermit_Send_Init *);
  530.  
  531. (*----------------------------------------------------------------------*)
  532. (* Build_And_Send_Packet_With_Retry --- Build & send packet with retry  *)
  533. (*----------------------------------------------------------------------*)
  534.  
  535. PROCEDURE Build_And_Send_Packet_With_Retry;
  536.  
  537. (*----------------------------------------------------------------------*)
  538. (*                                                                      *)
  539. (*     Procedure:  Build_And_Send_Packet_With_Retry                     *)
  540. (*                                                                      *)
  541. (*     Purpose:    Sends packet to remote Kermit and retries if         *)
  542. (*                 packet not acknowledged.                             *)
  543. (*                                                                      *)
  544. (*     Calling Sequence:                                                *)
  545. (*                                                                      *)
  546. (*        Build_And_Send_Packet_With_Retry;                             *)
  547. (*                                                                      *)
  548. (*                                                                      *)
  549. (*     Calls:                                                           *)
  550. (*                                                                      *)
  551. (*        Build_Packet                                                  *)
  552. (*        Check_ACK                                                     *)
  553. (*        Async_Flush_Output_Buffer                                     *)
  554. (*                                                                      *)
  555. (*----------------------------------------------------------------------*)
  556.  
  557. BEGIN (* Build_And_Send_Packet_With_Retry *)
  558.  
  559.                                    (* Build the packet *)
  560.    Build_Packet;
  561.                                    (* No tries yet *)
  562.    Try := 0;
  563.                                    (* Begin loop over sending tries *)
  564.    REPEAT
  565.                                    (* Send the packet *)
  566.       Send_Packet;
  567.                                    (* See if it was acknowledged *)
  568.       Check_ACK;
  569.                                    (* Increment count of send packet tries *)
  570.       Try := SUCC( Try );
  571.                                    (* If we're in a retry mode, and an    *)
  572.                                    (* XOFF was received, the XOFF may be  *)
  573.                                    (* spurious, so clear it before trying *)
  574.                                    (* again.  We also need to flush the   *)
  575.                                    (* comm output buffer at this point    *)
  576.                                    (* as well.                            *)
  577.                                    (*                                     *)
  578.                                    (* If an XOFF wasn't received, perhaps *)
  579.                                    (* the remote system got a spurious    *)
  580.                                    (* XOFF, so we send an XON.            *)
  581.                                    (*                                     *)
  582.  
  583.       IF ( Try > 2 ) THEN
  584.          IF Async_XOff_Received THEN
  585.             BEGIN
  586.                Async_Flush_Output_Buffer;
  587.                Async_XOff_Received := FALSE;
  588.                IF Do_Status_Line THEN
  589.                   Write_To_Status_Line( '             ', 65 );
  590.             END
  591.          ELSE
  592.             IF Async_Do_XonXoff THEN
  593.                Async_Send( CHR( XON ) );
  594.  
  595.                                    (* Stop if OK, abort requested, or too *)
  596.                                    (* many tries.                         *)
  597.  
  598.    UNTIL ACK_OK OR Kermit_Abort OR ( Try = Kermit_MaxTry );
  599.  
  600. END   (* Build_And_Send_Packet_With_Retry *);
  601.  
  602. (*----------------------------------------------------------------------*)
  603. (*      Kermit_Send_Header --- send file header (file name) packet      *)
  604. (*----------------------------------------------------------------------*)
  605.  
  606. PROCEDURE Kermit_Send_Header;
  607.  
  608. (*----------------------------------------------------------------------*)
  609. (*                                                                      *)
  610. (*     Procedure:  Kermit_Send_Header                                   *)
  611. (*                                                                      *)
  612. (*     Purpose:    Sends file name packet to remote Kermit.             *)
  613. (*                                                                      *)
  614. (*     Calling Sequence:                                                *)
  615. (*                                                                      *)
  616. (*        Kermit_Send_Header;                                           *)
  617. (*                                                                      *)
  618. (*     Calls:                                                           *)
  619. (*                                                                      *)
  620. (*        Build_And_Send_Packet_With_Retry                              *)
  621. (*                                                                      *)
  622. (*----------------------------------------------------------------------*)
  623.  
  624. BEGIN (* Kermit_Send_Header *)
  625.  
  626.                                    (* Construct file name packet *)
  627.  
  628.    Packet_Num          := SUCC( Packet_Num ) MOD 64;
  629.  
  630.    Send_Packet_Ptr^[4] := 'F';
  631.  
  632.    MOVE( FileName[1], Send_Packet_Ptr^[5], LENGTH( FileName ) );
  633.  
  634.    Send_Packet_Length := LENGTH( FileName ) + 4;
  635.  
  636.                                    (* Send the packet *)
  637.  
  638.    Build_And_Send_Packet_With_Retry;
  639.  
  640.                                    (* If it was ACKed, then *)
  641.                                    (* prepare to send file. *)
  642.    IF ACK_OK THEN
  643.       Kermit_State := Send_File
  644.    ELSE
  645.       BEGIN
  646.          Kermit_Abort := TRUE;
  647.          Kermit_State := Send_Break;
  648.       END;
  649.  
  650. END    (* Kermit_Send_Header *);
  651.  
  652. (*----------------------------------------------------------------------*)
  653. (*         Kermit_Send_Attributes --- send file attributes              *)
  654. (*----------------------------------------------------------------------*)
  655.  
  656. PROCEDURE Kermit_Send_Attributes;
  657.  
  658. (*----------------------------------------------------------------------*)
  659. (*                                                                      *)
  660. (*     Procedure:  Kermit_Send_Attributes                               *)
  661. (*                                                                      *)
  662. (*     Purpose:    Sends file attributes packet to remote Kermit.       *)
  663. (*                                                                      *)
  664. (*     Calling Sequence:                                                *)
  665. (*                                                                      *)
  666. (*        Kermit_Send_Attributes;                                       *)
  667. (*                                                                      *)
  668. (*     Calls:                                                           *)
  669. (*                                                                      *)
  670. (*        Build_And_Send_Packet_With_Retry                              *)
  671. (*                                                                      *)
  672. (*----------------------------------------------------------------------*)
  673.  
  674. VAR
  675.    L1               : INTEGER;
  676.    L2               : INTEGER;
  677.    L3               : INTEGER;
  678.    I                : INTEGER;
  679.    Send_Packet_Ptr2 : Kermit_Packet_Ptr;
  680.    Count            : INTEGER;
  681.    CheckSum         : INTEGER;
  682.  
  683. BEGIN  (* Kermit_Send_Attributes *)
  684.  
  685.                                    (* Increment packet number          *)
  686.  
  687.    Packet_Num := SUCC( Packet_Num ) MOD 64;
  688.  
  689.                                    (* We are going to send the file    *)
  690.                                    (* size in 8-bit characters and the *)
  691.                                    (* time and date the file was       *)
  692.                                    (* created.                         *)
  693.  
  694.    L1 := LENGTH( Kermit_CFile_Size );
  695.    L2 := LENGTH( Kermit_CFile_Date );
  696.    L3 := LENGTH( Kermit_CFile_Time );
  697.  
  698.    Send_Packet_Ptr^[ 4] := 'A';
  699.    Send_Packet_Ptr^[ 5] := '1';
  700.    Send_Packet_Ptr^[ 6] := CHR( 32 + L1 );
  701.  
  702.    MOVE( Kermit_CFile_Size[1] , Send_Packet_Ptr^[7] , L1 );
  703.    Send_Packet_Length   := L1 + 7;
  704.  
  705.    Send_Packet_Ptr^[Send_Packet_Length] := '#';
  706.    Send_Packet_Length                   := SUCC( Send_Packet_Length );
  707.    Send_Packet_Ptr^[Send_Packet_Length] := CHR( 32 + L2 + L3 + 1 );
  708.  
  709.    Send_Packet_Length   := SUCC( Send_Packet_Length );
  710.    MOVE( Kermit_CFile_Date[1] , Send_Packet_Ptr^[Send_Packet_Length] , L2 );
  711.    Send_Packet_Length   := Send_Packet_Length + L2;
  712.  
  713.    Send_Packet_Ptr^[Send_Packet_Length] := ' ';
  714.    Send_Packet_Length                   := SUCC( Send_Packet_Length );
  715.  
  716.    MOVE( Kermit_CFile_Time[1] , Send_Packet_Ptr^[Send_Packet_Length] , L3 );
  717.    Send_Packet_Length   := Send_Packet_Length + L3 - 1;
  718.  
  719.                                    (* Build packet and sent it         *)
  720.  
  721.    Build_And_Send_Packet_With_Retry;
  722.  
  723. END   (* Kermit_Send_Attributes *);
  724.  
  725.